package com.example.chapter03;

import com.example.common.Program;
import org.junit.Test;
import rx.Observable;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

import static com.packtpub.reactive.common.Helpers.debug;

/**
 * Created by user on 17/6/21.
 */
public class CreatingObservablesUsingVariousFactoryMethods implements Program {
    @Override
    public String name() {
        return "A few factory methods for creating Observables";
    }

    @Override
    public int chapter() {
        return 3;
    }

    @Override
    public void run() {
        subscribePrint(Observable.interval(500L, TimeUnit.MILLISECONDS),
                "Interval Observable");

        subscribePrint(Observable.timer(0L, 1L, TimeUnit.SECONDS),
                "Timed Interval Observable");

        subscribePrint(Observable.timer(1L, TimeUnit.SECONDS),
                "Timer Observable");

        subscribePrint(Observable.error(new Exception("Test Error!")),
                "Error Observable");

        subscribePrint(Observable.empty(), "Empty Observable");
        subscribePrint(Observable.never(), "Never Observable");

        subscribePrint(Observable.range(1, 10), "Range Observable");

        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
        }

    }

    private <T> void subscribePrint(Observable<T> observable, String name) {
        observable.subscribe(
                (v) -> System.out.println(name + " : " + v),
                (e) -> {
                    System.err.println("Error from " + name + ":");
                    System.err.println(e.getMessage());
                },
                () -> System.out.println(name + " ended!")
        );
    }

    public static void main(String[] args) {
        new CreatingObservablesUsingVariousFactoryMethods().run();
    }

    @Test
    public void zip(){
        Observable<Integer> zip = Observable
                .zip(
                        Observable.just(1, 3, 4),
                        Observable.just(5, 2, 6),
                        (a, b) -> a + b
                );
        subscribePrint(zip, "Simple zip");
    }

    @Test
    public void interval() throws InterruptedException {
        Observable<String> timedZip = Observable
                .zip(
                        Observable.from(Arrays.asList("Z", "I", "P", "P")),
                        Observable.interval(300L, TimeUnit.MILLISECONDS),
                        (value, i) -> value
                );
        subscribePrint(timedZip, "Timed zip");
        Thread.sleep(20000);
    }

    @Test
    public void combine() throws InterruptedException {
        Observable<String> greetings = Observable
                .just("Hello", "Hi", "Howdy", "Zdravei", "Yo", "Good to see ya")
                .zipWith(
                        Observable.interval(1L, TimeUnit.SECONDS),
                        this::onlyFirstArg
                );
        Observable<String> names = Observable
                .just("Meddle", "Tanya", "Dali", "Joshua")
                .zipWith(
                        Observable.interval(1500L, TimeUnit.MILLISECONDS),
                        this::onlyFirstArg
                );
        Observable<String> punctuation = Observable
                .just(".", "?", "!", "!!!", "...")
                .zipWith(
                        Observable.interval(1100L, TimeUnit.MILLISECONDS),
                        this::onlyFirstArg
                );

        Observable<String> combined = Observable
                .combineLatest(
                        greetings, names, punctuation,
                        (greeting, name, puntuation) ->
                                greeting + " " + name + puntuation)
                ;
        subscribePrint(combined, "Sentences");

        Thread.sleep(20000);
    }

    @Test
    public void schedule(){
        Observable
                .range(5, 5)
                .doOnEach(debug("Test", ""))
                .subscribe();
    }

    public <T, R> T onlyFirstArg(T arg1, R arg2) {
        return arg1;
    }
}
